package com.director.struts;

import com.director.core.DirectAction;
import com.director.core.DirectContext;
import com.director.core.DirectException;
import com.director.core.DirectMethod;
import com.director.core.DirectTransactionData;
import com.director.core.DirectTransactionResult;
import com.director.core.ExecutorAdapter;
import com.director.core.json.JsonParser;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.ActionProxyFactory;
import com.opensymphony.xwork2.ValidationAware;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.inject.Inject;

import java.util.HashMap;

/**
 * Author: Simone Ricciardi
 * Date: 2-lug-2010
 * Time: 16.34.32
 */
public class StrutsExecutorAdapter implements ExecutorAdapter {

   private Container container;
   private ActionProxyFactory actionProxyFactory;

   @Inject
   public void setContainer(Container container) {
      this.container = container;
   }

   @Inject
   public void setActionProxyFactory(ActionProxyFactory actionProxyFactory) {
      this.actionProxyFactory = actionProxyFactory;
   }

   public DirectTransactionResult execute(DirectAction directAction, DirectMethod directMethod, DirectTransactionData data) throws DirectException {

      HashMap<String, Object> extraContext = new HashMap<String, Object>();
      extraContext.put(ActionContext.VALUE_STACK, ActionContext.getContext().getValueStack());
      extraContext.put(ActionContext.PARAMETERS, ActionContext.getContext().getParameters());
      extraContext.put(DirectActionInvocation.DIRECT_ACTION, directAction);
      extraContext.put(DirectActionInvocation.DIRECT_METHOD, directMethod);

      ActionInvocation inv = new DirectActionInvocation(
            extraContext,
            directAction.getActionClass(),
            directMethod.getMethod(),
            directMethod.parseParameters(data)
      );
      this.container.inject(inv);
      
      ActionProxy proxy = this.actionProxyFactory.createActionProxy(
            inv,
            directAction.getNamespace(),
            directMethod.getName(),
            directMethod.getMethodName(),
            false,
            false
      );
      try {
         proxy.execute();
      } catch(Exception e) {
         throw new DirectException(e);
      }

      Object action = proxy.getAction();
      if(action instanceof ValidationAware) {
         ValidationAware validationAware = ((ValidationAware) action);
         if(validationAware.hasActionMessages()) {
            for (String message : validationAware.getActionMessages()) {
               DirectContext.get().pushEvent(new ValidationAwareEvent("actionMessage", message));
            }
         }
         if(validationAware.hasActionErrors()) {
            for (String error : validationAware.getActionErrors()) {
               DirectContext.get().pushEvent(new ValidationAwareEvent("actionError", error));
            }
         }
      }

      Object result = proxy.getInvocation().getInvocationContext().get(DirectActionInvocation.DIRECT_ACTION_RESULT);
      JsonParser parser = DirectContext.get().getConfiguration().getParser();
      return parser.buildResult(directMethod, result);
   }

}
